package TouristManagement.Client.Tourist;

import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.TreeMap;

import util.Convert;

import TouristManagement.*;

public class TouristClient {
	private TouristOffice leTouristOffice;
	private ArrayList<Site> lesSites = new ArrayList<Site>();
	private short touristCardNumber;
	private Site leSiteVisitActuel;
	private ServerNamingTourist leServerNamingTourist;
	
	
	/*
	 * création de l'objet tourist
	 */
	public TouristClient() {		
		this.touristCardNumber = 0;
	}
	
	/*
	 * Initialisation des servers
	 */
	public void initServer(){
		this.connectToServerNamingTourist();
		this.connectToTouristOfficeServer();
		this.connectToSiteServers();
	}	
	
	public void connectToServerNamingTourist(){
		//init VisitManagement server
		try {
			
	        String args[]=null;

			// Intialisation de l'orb
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));

	        // Construction du nom a rechercher
	        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
	         nameToFind[0] = new org.omg.CosNaming.NameComponent("ServerNamingTourist","");

	        // Recherche aupres du naming service
	        org.omg.CORBA.Object distantServerNamingTourist = nameRoot.resolve(nameToFind);
	        
	        leServerNamingTourist = ServerNamingTouristHelper.narrow(distantServerNamingTourist);
	        
	        System.out.println("Tourist naming server connected.");
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}	
	
	/*
	 * acheter une carte de visite
	 * input : nom du tourist, date de début et date de fin de validité de la carte
	 * ouput : numéro de la	carte si c'est ok, -1 sinon
	 */
	public short purchaseCard(String nom, Date startDate, Date endDate){				
		
		//ideintifier la date du jour
		DateV start = Convert.dateToDateV(startDate);
		DateV end = Convert.dateToDateV(endDate);
		
        //acheter la carte et enregistrer le numéro de la carte
        touristCardNumber = leTouristOffice.purchaseCard(nom, start, end);
        return touristCardNumber;
	}	
	
	public boolean verifyExistTourist(short touristCardNumber) {
		return leTouristOffice.existTourist(touristCardNumber);
	}
	
	public void setTouristCardNumber(short touristCardNumber) {
		this.touristCardNumber = touristCardNumber;
	}

	public InfoSite[] consultListeSites() {
		
		//create an random GPS		
		//retourner un valeur random entre 0 et 100 (minutes)
		Random rd = new Random();
		int x = rd.nextInt(100)+1;
		int y = rd.nextInt(100)+1;
		CoordsGPS position = new CoordsGPS ((short)x,(short)y);
		System.out.println("Your current GPS position is (" + x + "," + y + ").");
		System.out.println("Asking the tourist office server...");
		InfoSite[] result = leTouristOffice.consultListeSites(touristCardNumber, position);		
		return result;
	}	
	
	public void connectToTouristOfficeServer(){
		try {
			
			Properties props = new Properties();
	        props.put("org.omg.CORBA.ORBInitialPort", "2001");
	        props.put("org.omg.CORBA.ORBInitialHost", "127.0.0.1");
	        
	        String args[] = null;

			// Intialisation de l'orb
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));

	        // Construction du nom a rechercher
	        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
	         nameToFind[0] = new org.omg.CosNaming.NameComponent(leServerNamingTourist.nomTouristOffice(),"");

	        // Recherche aupres du naming service
	        org.omg.CORBA.Object distantTouristOffice = nameRoot.resolve(nameToFind);
	        leTouristOffice = TouristOfficeHelper.narrow(distantTouristOffice);
	        System.out.println("OfficeTourist connected.");
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}
	
	public void connectToSiteServers(){
		try {			
			
			short[] lesIdSites = leTouristOffice.getIdSite();
			
	        String args[] = null;

			// Intialisation de l'orb
			org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

	        // Recuperation du naming service
	        org.omg.CosNaming.NamingContext nameRoot =
	        		org.omg.CosNaming.NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
	        
	        //connect to sites
	        for (short i:lesIdSites){
		        // Construction du nom a rechercher
		        org.omg.CosNaming.NameComponent[] nameToFind = new org.omg.CosNaming.NameComponent[1];
		         nameToFind[0] = new org.omg.CosNaming.NameComponent(leServerNamingTourist.nomSites()[i-1],"");
	
		        // Recherche aupres du naming service
		        org.omg.CORBA.Object distantSite = nameRoot.resolve(nameToFind);
		        System.out.println("Site "+ leServerNamingTourist.nomSites()[i-1] + " connected, id "+i);
		        
		        lesSites.add(SiteHelper.narrow(distantSite));	 
	        }	        
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}

	public void checkOut(int advice) {	
//		//request the advice of the visitor
		Advice leAdvice;
		//convert to advice type		
		switch (advice) {
		case 1: 
			leAdvice = Advice.NotInteresting;
			break;
		case 2: 
			leAdvice = Advice.Marginal;
			break;
		case 3: 
			leAdvice = Advice.Interesting;
			break;
		case 4: 
			leAdvice = Advice.Worthly;
			break;
		case 5: 
			leAdvice = Advice.MustVisit;
			break;
		default:
			leAdvice = null;				
		}		
		if (leAdvice != null) {
			//check out the visitor and retrieve the VisitManagement object
			VisitManagement leVisitManagement = leSiteVisitActuel.checkOut(touristCardNumber);
			//add advice by using VisitManagement object		
			leVisitManagement.addAdvice(leSiteVisitActuel.idSite(), touristCardNumber, leAdvice);
			//re-initialiser le site visit actul (set null)
			leSiteVisitActuel = null;
		}
	}
	
	/*
	 * return une liste des idSite et leurs noms
	 */
	public Map<Short,String> getListSite(){
		Map<Short,String> result = new TreeMap<Short,String>();
		for (Site s:lesSites) {
			System.out.println(s.idSite()+". "+s.getNomSite());
			result.put(s.idSite(), s.getNomSite());			
		}		
		return result;
	}

	public String checkIn(short idSite) {	
		if (idSite>=lesSites.size()+1) Thread.currentThread().interrupt();
		else 
		{
			//if the tourist choose to visit a site
			for (Site s:lesSites) {
				//affect the site to site visit actual
				if (idSite==s.idSite()) {
					leSiteVisitActuel=s;					
				}
			}
			try 
			{
				System.out.println("Connecting to " + leSiteVisitActuel.getNomSite());
				leSiteVisitActuel.checkIn(touristCardNumber);
			} 
			catch (CheckInNotValid e) 
			{			
				//supprimer le visit actuel
				leSiteVisitActuel = null;
				return e.cause;
			}
		}
		return "Check in OK";
	}
	
	/*
	 * verifier si le tourist est en train de visiter un site 
	 */
	public boolean isVisitingSite() {		
		return (leTouristOffice.isVisitingSite(touristCardNumber));
	}
	
	/*
	 * get le site où le tourist est en train de visiter 
	 */
	public void initialiseVisitingSite() {		
		if (this.isVisitingSite()) {
			leSiteVisitActuel = leTouristOffice.siteVisiting(touristCardNumber);
		}	
	}
}
